﻿@using FluentValidation
@using System.Text.RegularExpressions
@using Egroo.UI.Constants;
@using System.Text.Json
@using Egroo.UI.Components.Layout;
@using Egroo.UI.Models;
@using jihadkhawaja.chat.client
@using jihadkhawaja.chat.client.Core
@using jihadkhawaja.chat.client.Services

@inject StorageService StorageService
@inject SessionStorage SessionStorage
@inject NavigationManager NavigationManager
@inject IChatAuth ChatAuthService
@inject IChatUser ChatUserService

<MudContainer MaxWidth="MaxWidth.Large" Class="my-10 pt-8">
    <MudIconButton Icon="@Icons.Material.Filled.Home" Href="/" Size="Size.Large" Class="mb-4" />
    <MudText GutterBottom Color="Color.Secondary" Typo="Typo.h6">Sign Up</MudText>
    <MudText>Already have an account? <span><MudButton Href="signin">SIGNIN</MudButton></span></MudText>

    <MudGrid Class="mt-8" Justify="Justify.Center">
        <MudItem xs="12" sm="8" md="6">
            <MudCard Elevation="25" Class="rounded-lg pb-4">
                <MudCardHeader>
                    <CardHeaderContent>
                        <MudText Typo="Typo.h5" Align="Align.Center">Create Account</MudText>
                    </CardHeaderContent>
                </MudCardHeader>
                <MudCardContent>
                    <MudForm Model="@model" @ref="@form" Validation="@(UserValidator.ValidateValue)" ValidationDelay="0">
                        <MudTextField @bind-Value="model.Username"
                                      For="@(() => model.Username)"
                                      Immediate="true" Required
                                      Label="Username" ErrorText="Invalid username." />

                        <MudTextField @bind-Value="model.Password"
                                      For="@(() => model.Password)"
                                      Immediate="true" Required
                                      T="string" Label="Password" HelperText="Choose a strong password" @ref="pwField1"
                                      InputType="InputType.Password" />

                        <MudTextField T="string"
                                      Label="Password" HelperText="Repeat the password" InputType="InputType.Password"
                                      Validation="@(new Func<string, string>(PasswordMatch))" Required />

                    </MudForm>
                </MudCardContent>
                <MudCardActions Class="d-flex justify-center">
                    <MudButton OnClick="Submit" Disabled=@IsBusy ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Primary" Size="Size.Large" Style="width:50%;">SUBMIT</MudButton>
                </MudCardActions>
            </MudCard>
        </MudItem>
    </MudGrid>
</MudContainer>

@code {
    [Inject] ISnackbar Snackbar { get; set; }
    MudForm form;

    UserFluentValidator UserValidator;

    MudTextField<string> pwField1;
    User model = new User();
    bool IsBusy = false;

    protected override void OnInitialized()
    {
        UserValidator = new UserFluentValidator(ChatUserService);

        base.OnInitialized();
    }

    private async Task Submit()
    {
        IsBusy = true;

        await form.Validate();

        if (!form.IsValid)
        {
            Snackbar.Add("Please be sure to fill all fields.", MudBlazor.Severity.Error);
            IsBusy = false;
            return;
        }

        dynamic dynamicObj = await ChatAuthService.SignUp(model.Username, model.Password);
        Dictionary<string, object> result = null;
        if (dynamicObj is not null)
        {
            result = JsonSerializer.Deserialize<Dictionary<string, object>>(dynamicObj);
        }

        //create user
        if (result is not null)
        {
            Guid Id = Guid.Parse(result["id"].ToString());
            string Token = result["token"].ToString();

            User user = new()
            {
                Id = Id,
            };

            switch (ClientModel.CurrentFrameworkPlatform)
            {
                case FrameworkPlatform.MAUI:
                    StorageService.CreateDirectory(ClientModel.AppDataPath);
                    StorageService.WriteToJsonFile("token", ClientModel.AppDataPath, Token, false, true);
                    break;
                case FrameworkPlatform.WASM:
                case FrameworkPlatform.SERVER:
                    await StorageService.SetLocalStorage("token", Token);
                    break;
                default:
                    throw new Exception("CurrentFrameworkPlatform parameter is undefined.");
            }

            SessionStorage.User = user;

            MobileChatSignalR.Initialize(Source.HubConnectionURL, SessionStorage.Token);
            await MobileChatSignalR.HubConnection.StartAsync();

            NavigationManager.NavigateTo("/channels", true);
        }
        else
        {
            Snackbar.Add("Failed to sign up, Please try again", MudBlazor.Severity.Error);
        }

        IsBusy = false;
    }

    private string PasswordMatch(string arg)
    {
        if (pwField1.Value != arg)
            return "Passwords don't match";
        return null;
    }

    public class UserFluentValidator : AbstractValidator<User>
    {
        private readonly IChatUser ChatUserService;
        public UserFluentValidator(IChatUser ChatUserService)
        {
            this.ChatUserService = ChatUserService;

            RuleFor(x => x.Username)
            .Cascade(CascadeMode.Stop)
                .NotEmpty()
                .Matches(@"^[a-zA-Z0-9_]{3,16}$")
                .WithMessage("Username must be between 3 and 16 characters, and can only contain letters, numbers, and underscores.");

            RuleFor(x => x.Password)
                .Cascade(CascadeMode.Stop)
                .NotEmpty()
                .Matches(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^a-zA-Z0-9]).{8,}$")
                .WithMessage("Password must be at least 8 characters long, contain at least one uppercase letter, one lowercase letter, one number, and one symbol.");
        }

        public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
        {
            var result = await ValidateAsync(ValidationContext<User>.CreateWithOptions((User)model, x => x.IncludeProperties(propertyName)));
            if (result.IsValid)
                return Array.Empty<string>();
            return result.Errors.Select(e => e.ErrorMessage);
        };
    }
}
